#ifndef __CASE_TPL_QUEUE_H__
#define __CASE_TPL_QUEUE_H__

#include "common_types.h"
#include "basic/tpl_queue.h"

class Test_tpl_queue : public testing::Test
{
  protected:
    __thread_safe__::tpl_queue<AA> g_queue;
    __thread_safe__::tpl_queue<AA> g_queue_done;
    virtual void SetUp(){};
    virtual void TearDown(){};
};

TEST_F(Test_tpl_queue, GetSize_IsEmpty)
{
    g_queue.Push(new AA(1));
    g_queue.Push(new AA(2));
    g_queue.Push(new AA(3));
    g_queue.Push(new AA(4));
    g_queue.Push(new AA(5));
    ASSERT_EQ(g_queue.GetSize(), 5);
    AA* pAA = g_queue.Pop();
    ASSERT_EQ(g_queue.GetSize(), 4);
    ASSERT_EQ(g_queue.IsEmpty(), false);
    delete pAA;
    pAA = g_queue.Pop();
    ASSERT_EQ(g_queue.GetSize(), 3);
    ASSERT_EQ(g_queue.IsEmpty(), false);
    delete pAA;
    pAA = g_queue.Pop();
    ASSERT_EQ(g_queue.GetSize(), 2);
    ASSERT_EQ(g_queue.IsEmpty(), false);
    delete pAA;
    pAA = g_queue.Pop();
    ASSERT_EQ(g_queue.GetSize(), 1);
    ASSERT_EQ(g_queue.IsEmpty(), false);
    delete pAA;
    pAA = g_queue.Pop();
    ASSERT_EQ(g_queue.GetSize(), 0);
    ASSERT_EQ(g_queue.IsEmpty(), true);
    delete pAA;
}

TEST_F(Test_tpl_queue, Clear)
{
    const int M{10};
    AA* pAA[M];
    for (int i = 0; i < M; ++i)
    {
        AA* pAA2 = new AA(i);
        pAA[i] = pAA2;
        g_queue.Push(pAA2);
    }

    ASSERT_EQ(g_queue.GetSize(), M);
    g_queue.Clear();
    ASSERT_EQ(g_queue.GetSize(), 0);

    for (int i = 0; i < M; ++i)
    {
        delete pAA[i];
    }
}

TEST_F(Test_tpl_queue, value)
{
    g_queue.Push(new AA(1));
    g_queue.Push(new AA(2));
    g_queue.Push(new AA(3));
    AA* pAA = g_queue.Pop();
    ASSERT_EQ(pAA->GetI(), 1);
    pAA->SetI(10000);
    ASSERT_EQ(pAA->GetI(), 10000);

    delete pAA;
    pAA = g_queue.Pop();
    delete pAA;
    pAA = g_queue.Pop();
    delete pAA;
}

TEST_F(Test_tpl_queue, Push_Pop)
{
    g_queue.Push(new AA(1));
    g_queue.Push(new AA(2));
    AA* pAA = g_queue.Pop();
    ASSERT_NE(pAA, nullptr);
    ASSERT_EQ(pAA->GetI(), 1);
    g_queue.Push(pAA);
    pAA = g_queue.Pop();
    ASSERT_EQ(pAA->GetI(), 2);
    g_queue.Push(pAA);
    pAA = g_queue.Pop();
    ASSERT_EQ(pAA->GetI(), 1);

    delete pAA;
    pAA = g_queue.Pop();
    delete pAA;

    pAA = g_queue.Pop();
    ASSERT_EQ(pAA, nullptr);
    pAA = g_queue.Pop();
    ASSERT_EQ(pAA, nullptr);
}

TEST_F(Test_tpl_queue, Remove)
{
    g_queue.Push(new AA(1));
    AA* pAA = new AA(2);
    g_queue.Push(pAA);
    g_queue.Push(new AA(3));

    bool b{false};
    b = g_queue.Remove(pAA);
    ASSERT_EQ(b, true);
    ASSERT_EQ(g_queue.GetSize(), 2);
    delete pAA; /// delete yourself, queue has no right to delete;
    b = g_queue.Remove(nullptr);
    ASSERT_EQ(b, false);
    ASSERT_EQ(g_queue.GetSize(), 2);
    pAA = new AA(1000);
    b = g_queue.Remove(pAA);
    ASSERT_EQ(b, false);
    ASSERT_EQ(g_queue.GetSize(), 2);
    delete pAA;

    pAA = g_queue.Pop();
    delete pAA;
    pAA = g_queue.Pop();
    delete pAA;
}

TEST_F(Test_tpl_queue, PushAndPop_1000000_TimeCost)
{
    const int M{1000000};
    for (int i = 0; i < M; ++i)
    {
        g_queue.Push(new AA(i));
    }
    ASSERT_EQ(g_queue.GetSize(), M);
    for (int i = 0; i < M; ++i)
    {
        AA* pAA = g_queue.Pop();
        delete pAA;
    }
}

#endif
